/*
 * 教材中的示例程序之完整版.
 * 书名：《编译原理基础》
 * 版次：第三版
 * 作者：王献青，张立勇，张淑平，刘坚
 * 出版社：西安电子科技大学出版社
 * 程序完成时间：2025.03
 */

//
// 文件内容：手工编码的识别函数
//

#include "lexer.h"

static TokenKind  recognize_num();
static TokenKind  recognize_id();

//手工编码的识别函数: 递归下降式
//::  教材程序清单2.4
TokenKind recognize_word_hand_coded()
{
    char  c2, c1 = *forward;            // 读取第一个字符
    if ( IS_EOF (c1) ) return EOFS;     // 通知调用者：输入已分析结束
    switch ( c1 ) {                     // 先根据第一个字符分情况处理
        case '<':
            c2 = *(++forward);          // 读取第二个字符
            if ( c2 == '=' )  return LE;
            else { --forward; return LT; }  // 退回其他字符，返回LT
        case '!':
            c2 = *(++forward);          // 读取第二个字符
            if ( c2 == '=' )  return NE;
            else { --forward; return NOT; } // 退回其他字符，返回NOT
        case '=':
            c2 = *(++forward);          // 读取第二个字符
            if ( c2 == '=' )  return EQ;
            else { --forward; return ASSIGN; } // 退回其他字符，返回ASSIGN
        case '>':
            c2 = *(++forward);          // 读取第二个字符
            if ( c2 == '=' )  return GE;
            else { --forward; return GT; } // 退回其他字符，返回GT
        default:    // 其他情况
            if ( IS_LETTER (c1) ) {   // 状态 10 下
                // 识别标识符, c1 是其第一个字符，是某个字母或下划线
                return recognize_id ();
            }
            else if ( IS_DIGIT (c1) ) {    // 状态 12 下
                // 识别数字字面量，c1 是其第一个字符，是某个数字字符
                return recognize_num ();
            }
            else { return ERROR; }     // 无效字符
    }  // switch(c1) 结束
}


// 识别标识符中第2个字符及之后的内容
static TokenKind  recognize_id() {
    char c2 = *(++forward);   // 标识符的后续字符或下一单词开始
    while ( IS_LETTER (c2) || IS_DIGIT (c2) ) c2 = *(++forward);
    --forward;    // 非字母/数字字符，退回给输入流
    return ID;
}

static TokenKind  recognize_exponent();

// 识别数字字面量中第2个字符及之后的内容
static TokenKind  recognize_num() {
    char c2 = *(++forward);  // 字面量的后续字符或下一单词开始
    while ( IS_DIGIT (c2) ) c2 = *(++forward); // 继续识别整数部分
    if ( c2 == '.' ) {      // 到达状态 13 后， 识别小数部分和可选的指数部分
        c2 = *(++forward);
        if ( ! IS_DIGIT(c2) ) {  // 小数点后面不是数字的处理
            // 这里的处理仅为演示：有些应用中，需要状态回退到
            //   最近一次经历的终态
            --forward; --forward;
            return INT;  // 接受整数部分
        }

        while ( IS_DIGIT (c2) ) c2 = *(++forward); // 状态14下， 识别小数部分
        if ( c2 != 'E' ) { // 状态14下， 小数后面没有指数部分
            --forward;
            return REAL;
        }
        return  recognize_exponent(); // 状态15下， 识别指数部分
    }
    else if ( c2 == 'E' ) { // 状态15下， 识别指数部分
        return  recognize_exponent();
    }
    else {  // 状态12下，遇到既不是点、也不是E的字符
        --forward;
        return INT;
    }
}


// 状态15下， 识别指数部分 E 之后的内容
static TokenKind  recognize_exponent() {
    char c = *(++forward);  // 指数部分,E的后续字符或下一单词开始
    if ( c == '+' || c == '-' )
        c = *(++forward);   // 到达状态16

    if ( ! IS_DIGIT(c) ) {  // 状态16或15下
        return ERROR;
    }

    //状态17下，识别指数中的数字
    while ( IS_DIGIT (c) ) c = *(++forward);
    --forward;
    return REAL;
}
